namespace Roids.SL.Framework
{
    using System;
    using Microsoft.Xna.Framework;

    public class SpriteSheet
    {
        private readonly int _spriteHeight = 64;
        private readonly Point<int> _spriteSheetSize;
        private readonly int _spriteWidth = 64;
        protected double FrameRate = 83f/1000; //in ms, 83 ~ 12fps 
        private int _currentFrame;
        private Point<int>[] _currentScene;
        private Point<int>[][] _scenes;
        private double _secondsUntilNextFrame;

        public SpriteSheet(int spriteHeight, int spriteWidth, int spriteSheetWidth, int spriteSheetHeight)
        {
            _currentFrame = 0;
            _spriteHeight = spriteHeight;
            _spriteWidth = spriteWidth;
            _spriteSheetSize = new Point<int>(spriteSheetWidth, spriteSheetHeight);
        }

        private int SpriteSheetColumns
        {
            get { return (_spriteSheetSize.X/_spriteWidth); }
        }

        public void InitializeScenes(params int[] framesPerScene)
        {
            _secondsUntilNextFrame = FrameRate;

            _scenes = new Point<int>[framesPerScene.Length][];
            var startSceneAtFrame = 0;
            for (int scene = 0; scene < framesPerScene.Length; scene++)
            {
                _scenes[scene] = GetFramesForAnimation(startSceneAtFrame, framesPerScene[scene]);
                startSceneAtFrame += framesPerScene[scene];
            }
        }

        private Point<int>[] GetFramesForAnimation(int start, int count)
        {
            var row = start/SpriteSheetColumns;
            var col = start - ((row)*SpriteSheetColumns);
            var sceneFrames = new Point<int>[count];

            for (int i = 0; i < count; i++)
            {
                sceneFrames[i] = new Point<int>(col, row);

                if (col >= SpriteSheetColumns - 1)
                {
                    col = 0;
                    row++;
                }
                else
                {
                    col++;
                }
            }

            return sceneFrames;
        }

        public Rectangle GetBoundsForFrame(int sceneId, GameTime gameTime)
        {
            _currentScene = _scenes[sceneId];

            _secondsUntilNextFrame -= gameTime.ElapsedGameTime.TotalSeconds;

            if (_secondsUntilNextFrame < 0)
            {
                _secondsUntilNextFrame = FrameRate;
                _currentFrame = (_currentFrame + 1 < _currentScene.Length)
                                    ? _currentFrame + 1
                                    : 0;
            }

            var p = _currentScene[_currentFrame];

            var x = p.X*_spriteWidth;
            var y = p.Y*_spriteHeight;
            return new Rectangle(x, y, _spriteWidth, _spriteHeight);
        }

        public Rectangle GetBoundsForFrame(int sceneId, double position)
        {
            _currentScene = _scenes[sceneId];

            position = Math.Min(position, 1.0);

            _currentFrame = (position < 0)
                                ? 0
                                : (int) Math.Floor((_currentScene.Length - 1)*position);

            var p = _currentScene[_currentFrame];

            var x = p.X*_spriteWidth;
            var y = p.Y*_spriteHeight;
            return new Rectangle(x, y, _spriteWidth, _spriteHeight);
        }
    }
}